home *** CD-ROM | disk | FTP | other *** search
- Subject: v07i089: A simple BSD idle-users daemon
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: seismo!erix!mike (Mike Williams)
- Mod.sources: Volume 7, Issue 89
- Archive-name: idle.users
-
- Dear Moderator,
-
- Please find within the source code for a daemon I have been running for
- more than 6 months without problems on our 4.2BSD system. It simply
- logs off idle users afer giving them fair warning. See comments at the
- start of the code for more details.
-
- I wrote this thing after I noticed the some users never logged off. I
- have seen similar things on the net before, but they all seemed rather
- complicated, whereas this thing is very simple and easy to use and
- configure. Maybe the config data should be read from a file, I thought
- of this but felt that the thing is so seldom reconfigured that this
- seemed unecessary. Have not put in any comments about this being public
- domain etc, but of course anyone can use this exactly as they want as
- far as I am concerned.
-
- Mike Williams (mike@erix.UUCP or ...mcvax!enea!erix!mike)
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If all goes well, you will see the message "End of shell archive."
- # Contents: Makefile idel.c
- PATH=/bin:/usr/bin:/usr/ucb; export PATH
- echo shar: extracting "'Makefile'" '(46 characters)'
- if test -f 'Makefile' ; then
- echo shar: will not over-write existing file "'Makefile'"
- else
- sed 's/^X//' >Makefile <<'@//E*O*F Makefile//'
- X
- Xidel: idel.c
- X $(CC) $(CFLAGS) -o idel idel.c
- @//E*O*F Makefile//
- if test 46 -ne "`wc -c <'Makefile'`"; then
- echo shar: error transmitting "'Makefile'" '(should have been 46 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'idel.c'" '(5448 characters)'
- if test -f 'idel.c' ; then
- echo shar: will not over-write existing file "'idel.c'"
- else
- sed 's/^X//' >idel.c <<'@//E*O*F idel.c//'
- X/* idles deamon - kills off users who have not used their terminals for
- X * a specified time.
- X * Tested and run for 6 month on 4.2 BSD at site Erix.
- X * Change LMESSAGE, WMESSAGE, DAYOUY, NIGHTO, EVENING, MORNING and SLEEP
- X * to what you want locally (see comments in code) compile and run (as root).
- X * preferably started in /etc/rc.local by lines something like this:
- X * if [ -f /usr/local/lib/id ]; then
- X * /usr/local/lib/id & echo -n ' idle' >/dev/console
- X * fi
- X * when starting local daemons.
- X * The daemon wakes up every SLEEP minutes, reads UTMP and stats the terminals
- X * to see if when they were last used. A warning (WMESSAGE) is sent if the
- X * time elapsed excedes time WARN minutes. The user is logged out and a message
- X * (LMESSAGE) is sent if the user has been idle for more than DAYOUT minutes
- X * between the hours MORNING to EVENING or else NIGHTO minutes. Error messages
- X * are sent to syslog LOG_CRIT. A log of users logged out is sent to syslog
- X * LOG_INFO. Useful for defending system managers from irate users who do
- X * something stupid and log themselves out and then blame the daemon!
- X */
- X#include <utmp.h>
- X#include <sys/types.h>
- X#include <sys/time.h>
- X#include <sys/stat.h>
- X#include <sys/file.h>
- X#include <sgtty.h>
- X#include <syslog.h>
- X#include <setjmp.h>
- X#include <signal.h>
- X#include <strings.h>
- X#define UTMP "/etc/utmp"
- X#define LMESSAGE "\007\007\rAuto logout - too long idle time\r\n"
- X#define WMESSAGE "\007\007\rThe idle deamon has spotted you\r\n"
- X#define DAYOUT 480 /* logout after this number of idle minutes - daytime*/
- X#define NIGHTO 120 /* logout after this number of idle minutes - nightime */
- X#define MORNING 7 /* start of daytime */
- X#define EVENING 18 /* start of evening time */
- X#define WARN 90 /* start sending warnings after this time */
- X#define SLEEP 10 /* time (minutes) between each check */
- X
- Xjmp_buf env;
- Xstruct utmp ut;
- Xstruct stat sbuf;
- Xstruct timeval tv;
- Xstruct timezone tz;
- Xstruct tm *ltime;
- Xstruct stat sbuf;
- Xmain()
- X{
- X int fd, minutes, logout;
- X char fname[12];
- X#ifndef DEBUG
- X if (fork() != 0) exit(0); /* kill off parent */
- X /* close all files */
- X fd = getdtablesize();
- X for ( fd--; fd>=0; fd--){
- X (void) close(fd);
- X }
- X /* create files for std{in,out,err} if they are used by syslog or some
- X such stupidity */
- X if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
- X if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
- X if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
- X /* now remove the controling tty (if there is one) */
- X if ( (fd = open("/dev/tty", O_RDWR)) >= 0 ) {
- X (void) ioctl(fd, TIOCNOTTY, 0);
- X (void) close(fd);
- X }
- X#endif
- X
- X while (1) {
- X /* open the utmp file */
- X if ((fd = open(UTMP, O_RDONLY, 0)) < 0) {
- X syslog(LOG_CRIT, "Idles can't open utmp");
- X exit(1);
- X }
- X /* get the time */
- X if (gettimeofday(&tv, &tz) != 0) {
- X syslog(LOG_CRIT, "Idles can't get timeofday");
- X exit(1);
- X }
- X ltime = localtime(&tv.tv_sec);
- X /* work out the logout time limit */
- X if ((ltime->tm_hour > MORNING) && (ltime->tm_hour < EVENING)) {
- X logout = DAYOUT;
- X }
- X else logout = NIGHTO;
- X
- X /* read the utmp file, record by record until finished */
- X while (read(fd, &ut, sizeof(struct utmp)) == sizeof(struct utmp)) {
- X if (ut.ut_line[0] != '\0' && ut.ut_name[0] != '\0') {
- X /* get the last time of use of the terminal by
- X stat-ing the terminal */
- X strcpy(fname, "/dev/");
- X strcat(fname, ut.ut_line);
- X if (stat(fname, &sbuf) != 0) {
- X perror("idles: stat: ");
- X continue;
- X }
- X /* calculate the number of minutes since the terminal was last
- X acessed */
- X minutes = (tv.tv_sec - sbuf.st_atime ) / 60;
- X /* kill him off or warn him if he hasn't used his terminal */
- X if (minutes >= logout) {
- X zap(fname, LMESSAGE, 0);
- X syslog(LOG_INFO, "Auto logout %s %s ",
- X ut.ut_name, ut.ut_line);
- X }
- X else if (minutes >= WARN) {
- X zap(fname, WMESSAGE, 1);
- X }
- X }
- X }
- X (void) close(fd);
- X /* sleep until its time to start again */
- X sleep(SLEEP * 60);
- X }
- X}
- X/* kill or warn a user */
- Xzap(fname, message, warn)
- Xchar *fname, *message;
- X{
- X int allarmed();
- X struct sgttyb ttyb;
- X int tfd;
- X if (fork() == 0) {
- X /* child kills the offender */
- X /* close all files */
- X tfd = getdtablesize();
- X for ( tfd--; tfd>=0; tfd--){
- X (void) close(tfd);
- X }
- X /* now remove the controling tty (if there is one) */
- X if ( (tfd = open("/dev/tty", O_RDWR)) >= 0 ) {
- X (void) ioctl(tfd, TIOCNOTTY, 0);
- X (void) close(tfd);
- X }
- X /* this open will also set a new controling terminal */
- X tfd = open(fname, O_RDWR, 0600) ;
- X if (tfd < 0) exit(1);
- X /* setup a timeout if against all odds we get hung */
- X signal(SIGALRM,allarmed);
- X alarm(2);
- X if (setjmp(env) == 0) {
- X /* do this to prevent ^S from hanging the process */
- X (void) ioctl(tfd, TIOCSTART, (char *)0);
- X /* toggle cbreak to disrupt any terminal paging */
- X (void) ioctl(tfd, TIOCGETP, &ttyb);
- X ttyb.sg_flags ^= CBREAK;
- X (void) ioctl(tfd, TIOCSETP, &ttyb);
- X ttyb.sg_flags ^= CBREAK;
- X (void) ioctl(tfd, TIOCSETP, &ttyb);
- X
- X /* write out the logout message */
- X write(tfd, message, strlen(message));
- X
- X /* flush it out for safety's sake */
- X (void) ioctl(tfd, TIOCFLUSH, (char *)0);
- X }
- X alarm(0);
- X (void) close(tfd);
- X /* kill off the offender's login and exit */
- X if (!warn) vhangup();
- X exit(0);
- X }
- X /*parent: wait for the forked process*/
- X while (wait(0) == 0);
- X}
- X
- X/* just longjmp out if timed out (SIGALRM received) */
- Xallarmed(sig)
- Xint sig;
- X{
- Xlongjmp(env,1);
- X}
- X
- @//E*O*F idel.c//
- if test 5448 -ne "`wc -c <'idel.c'`"; then
- echo shar: error transmitting "'idel.c'" '(should have been 5448 characters)'
- fi
- fi # end of overwriting check
- echo shar: "End of shell archive."
- exit 0
-